package com.liu.yupao.job;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.liu.yupao.mapper.UserMapper;
import com.liu.yupao.model.entity.User;
import com.liu.yupao.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author lqh
 * @since 2025-09-19 15:45
 * 推荐用户定时缓存预热
 */
@Component
@Slf4j
public class PreCacheJob {

    @Resource
    private UserMapper userMapper;

    @Resource
    private UserService userService;

    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    @Resource
    private RedissonClient redissonClient;


    /**
     * 每天凌晨执行一次预热
     */
    @Scheduled(cron = "00 0 0 * * ?")
     public void prepareCache(){
        ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue ();
        //给所有用户缓存预热（可以给指定重要用户（VIP）缓存，其他不缓存）
        List<User> userList = userMapper.selectList (new QueryWrapper<> ());
        //获取一个分布式锁对象
        RLock lock = redissonClient.getLock ("yuPao.precacheJob:doCache:lock");
        //尝试获取锁
        try {
            //waitTime:0 (只有一个线程可以获取到锁,只抢一次，抢不到就返回false)  leaseTime:过期时间
            if (lock.tryLock (0,-1,TimeUnit.MILLISECONDS)){
                System.out.println ("获取锁成功: "+ Thread.currentThread ().getName ());
                for (User user : userList) {
                    String redisKey = String.format ("yuPao:user:recommend:%s", user.getId ());
                    //缓存10条数据
                    Page<User> userPage = userService.page (new Page<> (1, 10));
                    //放入redis缓存中
                    try {
                        // 获取当前时间
                        LocalDateTime now = LocalDateTime.now ();
                        // 计算次日凌晨时间（今天的24:00:00）
                        LocalDateTime nextMidnight = now.plusDays (1).withHour (0).withMinute (0)
                                .withSecond (0).withNano (0);
                        // 计算两个时间之间的差值
                        Duration duration = Duration.between (now, nextMidnight);
                        // 转换为秒数
                        long secondsToMidnight = duration.getSeconds ();
                        //设置过期时间
                        opsForValue.set (redisKey, userPage, secondsToMidnight, TimeUnit.SECONDS);
                    } catch (Exception e) {
                        log.error ("redis set key error", e);
                    }
                }
            }else {
                System.out.println ("获取锁失败:"+ Thread.currentThread ().getName ());
            }
        } catch (InterruptedException e) {
            log.error ("Exception",e);
        }finally {
            //释放锁
            if (lock.isHeldByCurrentThread ()){
                try {
                    System.out.println ("释放锁成功: "+Thread.currentThread ().getName ());
                    lock.unlock ();
                }catch (Exception e){
                    log.error ("释放锁异常", e);
                }

            }
        }
    }
}
